from rest_framework.views import APIView
from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer
from django_redis import get_redis_connection
from rest_framework.response import Response
import pickle
import base64
from goods.models import SKU
from rest_framework import status


# Create your views here.

class CartView(APIView):
    """
    购物车

    POST /cart/ 添加商品到购物车
    """

    def perform_authentication(self, request):
        """
        重写父类的用户验证方法,不在进入视图就检查JWT
        """
        pass

    def post(self, request):
        # 获取数据进行校验
        # sku_id,count是必传参数，selected是可选参数
        data = request.data
        serializer = CartSerializer(data=data)
        serializer.is_valid()
        # 获取到验证过后的数据
        sku_id = serializer.data.get('sku_id')
        count = serializer.data.get('count')
        selected = serializer.data.get('selected')
        # 判断用户是否存在
        try:
            user = request.user
        except Exception:
            user = None
        # request.user.is_authenticated
        if user is not None and user.is_authenticated:
            # 用户已经登录，将数据保存到redis中
            # 连接redis数据库
            redis_conn = get_redis_connection('cart')
            # # 向redis中添加count数据
            # # hash: user.id {sku_id:count}
            # # redis_conn.hset('cart_%s'%user.id,sku_id,count)
            # # hincrby 实现增量
            # redis_conn.hincrby('cart_%s' % user.id, sku_id, count)
            # # 如果是被选中的商品，将sku_id添加到集合中
            # if selected:
            #     redis_conn.sadd('cart_selected_%s' % user.id, sku_id)

            # 创建管道实例
            pl = redis_conn.pipeline()
            pl.hincrby('cart_%s' % user.id, sku_id, count)
            pl.sadd('cart_selected_%s' % user.id, sku_id)

            # 统一让管道执行
            pl.execute()
            return Response(serializer.data)
        else:
            # 用户未登陆，将数据保存在cookie中
            # 将数据转换成cart数据，加密后保存到cookie中
            # {sku_id:{'count':xxx,'selected':xxx}}
            cart_str = request.COOKIES.get('cart')
            if cart_str is not None:
                cart_dict = pickle.loads(base64.b64decode(cart_str))
            else:
                cart_dict = {}
            # 如果添加到购物车的商品之前已经添加过了，修改count的值
            if sku_id in cart_dict:
                origin_count = cart_dict[sku_id]['count']
                count += origin_count
            cart_dict[str(sku_id)] = {
                'count': count,
                'selected': selected
            }
            response = Response(serializer.data)
            cart = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('cart', cart, 24 * 3600)
            return response

    def get(self, request):
        """
        思路
           #判断是否为登录用户
               #登录用户,从redis中获取数据
               #非登录用户,从cookie中获取数据
           #获取所有商品的信息
           #返回响应
        """
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            # 登录用户
            # 从redis中获取数据
            redis_conn = get_redis_connection('cart')
            # 获取hash
            redis_cart = redis_conn.hgetall('cart_%s' % user.id)
            # 获取set中选中ID
            redis_selected_id = redis_conn.smembers('cart_selected_%s' % user.id)
            cart = {}
            # 遍历出redis中的值，遍历成cart类型数据

            for sku_id, count in redis_cart.items():
                count = int(count.decode())
                cart[sku_id.decode()] = {
                    'count': int(count),
                    'selected': sku_id in redis_selected_id
                }
        else:
            # 未登录用户
            # 获取到cookie中的cart数据
            cart_str = request.COOKIES.get('cart')
            # 如果cart中有数据，对其解码
            if cart_str is not None:
                cart = pickle.loads(base64.b64decode(cart_str))
            else:
                cart = {}
        # 找出cart所包含的所有sku_id
        ids = cart.keys()
        skus = SKU.objects.filter(pk__in=ids)
        # 遍历每一个sku_id,对其添加属性
        for sku in skus:
            # 给对象动态添加属性
            sku.count = cart[str(sku.id)]['count']
            sku.selected = cart[str(sku.id)]['selected']

            # 5.再将商品信息通过序列化器转换为字典
        serializer = CartSKUSerializer(skus, many=True)

        return Response(serializer.data)

    def put(self, request):
        """
        只要修改，就把所有的数据都提交
        幂等，就是将最终的结果提交给后端， 也得把最终结果返回给前端

        # 1. 前段应该把sku_id,count必须传递过来，是否选中的状态是一个可选
        # 2. 我们就需要对前端提交的数据进行校验
        # 3. 校验完成之后，我们需要得到数据，然后将数据保存到指定的地方
        # 4. 获取登录的状态
        # 5. 登录用户保存在redis中
        # 6. 未登录用户保存在cookie中

        """
        # 获取前端传过来的数据
        data = request.data
        # 对数据进行校验
        serializer = CartSerializer(data=data)
        # 获取到验证过后的数据
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.data.get('sku_id')
        count = serializer.data.get('count')
        selected = serializer.data.get('selected')
        # 判断用户是否存在
        try:
            user = request.user
        except Exception:
            user = None
        # request.user.is_authenticated
        if user is not None and user.is_authenticated:
            # 连接redis数据库
            redis_conn = get_redis_connection('cart')
            # 重新设置redis中hash值
            redis_conn.hset('cart_%s' % user.id, sku_id, count)
            if selected:
                redis_conn.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                redis_conn.srem('cart_selected_%s' % user.id, sku_id)
            return Response(serializer.data)
        else:
            # 用户未登陆，将数据保存在cookie中
            # 将数据转换成cart数据，加密后保存到cookie中
            # {sku_id:{'count':xxx,'selected':xxx}}
            cart_str = request.COOKIES.get('cart')
            if cart_str is not None:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}
            # 对数据进行更新
            if sku_id in cart_dict:
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected
                }
            response = Response(serializer.data)
            cart = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('cart', cart, 24 * 3600)
            return response

    def delete(self, request):
        # 获取前端传过来的sku_id
        data = request.data
        serializer = CartDeleteSerializer(data=data)
        serializer.is_valid()
        sku_id = serializer.data.get('sku_id')
        try:
            user = request.user
        except Exception:
            user = None
        # request.user.is_authenticated
        if user is not None and user.is_authenticated:
            # 连接redis
            redis_conn = get_redis_connection('cart')
            redis_conn.hdel('cart_%s' % user.id, sku_id)
            redis_conn.srem('cart_selected_%s' % user.id, sku_id)
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            cart_str = request.COOKIES.get('cart')
            if cart_str is not None:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}
            response = Response(status=status.HTTP_204_NO_CONTENT)
            if sku_id in cart_dict:
                del cart_dict[sku_id]
                cart = base64.b64encode(pickle.dumps(cart_dict)).decode()
                response.set_cookie('cart', cart, 24 * 3600)
            return response
